#ifndef __MENU_HPP
#define __MENU_HPP

#include <gccore.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include <ogc/system.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <wiiuse/wpad.h>
#include <ogc/pad.h>

#include "safe_vector.hpp"
#include <map>
#include "config.hpp"
#include "cursor.hpp"
#include "gui.hpp"
#include "btnmap.h"
#include "homebrew.h"
#include "channels.h"
#include "devicemounter/DeviceHandler.hpp"
#include "sys.h"

using namespace std;

extern bool bootHB;

class CMenu
{
public:
	CMenu(CVideo &vid);
	~CMenu(void) {cleanup();}

	void init();
	void error(const wstringEx &msg);
	int main(void);
	void cleanup(void);
	void exitApp(bool withHB = false){m_exit = true; bootHB = withHB;};
private:
	struct SZone
	{
		int x;
		int y;
		int w;
		int h;
		bool hide;
	};
	CVideo &m_vid;
	CCursor m_cursor[WPAD_MAX_WIIMOTES];
	CButtonsMgr m_btnMgr;

	Config m_cfg;
	Config m_loc;
	Config m_loclist;
	Config m_cat;

	Config m_version;
	Config m_dump;
	Config m_newID;
	Channels m_channels;
	safe_vector<std::string> m_homebrewArgs;
	u8 m_aa;

	bool m_gamelistdump;
	bool m_locked;
	bool m_titles_loaded;
	s16 m_showtimer;
	std::string m_curLanguage;

	// 
	std::string m_themeDataDir;
	std::string m_appDir;
	std::string m_dataDir;
	std::string m_picDir;
	std::string m_boxPicDir;
	std::string m_cacheDir;
	std::string m_themeDir;
	std::string m_musicDir;
	std::string m_txtCheatDir;
	std::string m_cheatDir;
	std::string m_bcaDir;
	std::string m_wipDir;
	std::string m_altDolDir;
	std::string m_videoDir;
	std::string m_fanartDir;
	std::string m_screenshotDir;
	std::string m_settingsDir;
	std::string m_languagesDir;
	std::string m_wdmDir;
	/* Updates */
	const char* m_old_update_url;
	const char* m_app_update_url;
	const char* m_data_update_url;
	std::string m_dol;
	bool m_update_dolOnly;
	u32 m_dol_update_size;
	std::string m_app_update_zip;
	u32 m_app_update_size;
	std::string m_data_update_zip;
	u32 m_data_update_size;
	std::string m_ver;
	/* End Updates */
	// 
	STexture m_curBg;
//Error Messages 
	u32 m_errorLblMessage;
	u32 m_errorLblIcon;
//Main Config menus
	u32 m_configLblPage;
	u32 m_configBtnPageM;
	u32 m_configBtnPageP;
	u32 m_configBtnBack;
	u32 m_configLblTitle;
	u32 m_configLblBoxMode;
	u32 m_configBtnBoxMode;
	u32 m_configLblRumble;
	u32 m_configBtnRumble;
	u32 m_configLblDownload;
	u32 m_configBtnDownload; 
	u32 m_configLblParental;
	u32 m_configBtnUnlock;
	u32 m_configBtnSetCode;
	u32 m_configAdvLblTheme;
	u32 m_configAdvLblCurTheme;
	u32 m_configAdvBtnCurThemeM;
	u32 m_configAdvBtnCurThemeP;
	u32 m_configAdvLblLanguage;
	u32 m_configAdvLblCurLanguage;
	u32 m_configAdvBtnCurLanguageM;
	u32 m_configAdvBtnCurLanguageP;
	u32 m_config3LblGameLanguage;
	u32 m_config3LblLanguage;
	u32 m_config3BtnLanguageP;
	u32 m_config3BtnLanguageM;
	u32 m_config3LblGameVideo;
	u32 m_config3LblVideo;
	u32 m_config3BtnVideoP;
	u32 m_config3BtnVideoM;
	u32 m_config3LblErr2Fix;
	u32 m_config3BtnErr2Fix;
	u32 m_config3LblOcarina;
	u32 m_config3BtnOcarina;
	u32 m_config4LblReturnTo;
	u32 m_config4LblReturnToVal;
	u32 m_config4BtnReturnToM;
	u32 m_config4BtnReturnToP;
	u32 m_config4LblHome;
	u32 m_config4BtnHome;
	u32 m_config4LblSaveFavMode;
	u32 m_config4BtnSaveFavMode;
	u32 m_config4LblCategoryOnBoot;
	u32 m_config4BtnCategoryOnBoot;
	u32 m_configSndLblBnrVol;
	u32 m_configSndLblBnrVolVal;
	u32 m_configSndBtnBnrVolP;
	u32 m_configSndBtnBnrVolM;
	u32 m_configSndLblMusicVol;
	u32 m_configSndLblMusicVolVal;
	u32 m_configSndBtnMusicVolP;
	u32 m_configSndBtnMusicVolM;
	u32 m_configSndLblGuiVol;
	u32 m_configSndLblGuiVolVal;
	u32 m_configSndBtnGuiVolP;
	u32 m_configSndBtnGuiVolM;
	u32 m_configSndLblCFVol;
	u32 m_configSndLblCFVolVal;
	u32 m_configSndBtnCFVolP;
	u32 m_configSndBtnCFVolM;
	u32 m_configScreenLblTVHeight;
	u32 m_configScreenLblTVHeightVal;
	u32 m_configScreenBtnTVHeightP;
	u32 m_configScreenBtnTVHeightM;
	u32 m_configScreenLblTVWidth;
	u32 m_configScreenLblTVWidthVal;
	u32 m_configScreenBtnTVWidthP;
	u32 m_configScreenBtnTVWidthM;
	u32 m_configScreenLblTVX;
	u32 m_configScreenLblTVXVal;
	u32 m_configScreenBtnTVXM;
	u32 m_configScreenBtnTVXP;
	u32 m_configScreenLblTVY;
	u32 m_configScreenLblTVYVal;
	u32 m_configScreenBtnTVYM;
	u32 m_configScreenBtnTVYP;
	u32 m_config7LblPartitionName;
	u32 m_config7LblPartition;
	u32 m_config7BtnPartitionP;
	u32 m_config7BtnPartitionM;
	u32 m_config7LblAsyncNet;
	u32 m_config7BtnAsyncNet;
//Download menu
	u32 m_downloadLblTitle;
	u32 m_downloadPBar;
	u32 m_downloadBtnCancel;
	u32 m_downloadBtnVersion;
	u32 m_downloadLblMessage[2];

	static s8 _versionDownloaderInit(CMenu *m);
	static s8 _versionTxtDownloaderInit(CMenu *m);
	s8 _versionDownloader();
	s8 _versionTxtDownloader();
// Parental code menu	
	u32 m_codeLblTitle;
	u32 m_codeBtnKey[10];
	u32 m_codeBtnBack;
	u32 m_codeBtnErase;
//About menu
	u32 m_aboutLblTitle;
	u32 m_aboutLblOrigAuthor;
	u32 m_aboutLblAuthor;
	u32 m_aboutLblInfo;
	u32 m_aboutLblIOS;
	u32 m_aboutBtnSystem;
// System Menu
	u32 m_systemBtnBack;
	u32 m_systemLblTitle;
	u32 m_systemLblVersionTxt;
	u32 m_systemLblVersion;
	u32 m_systemLblVersionRev;
	u32 m_systemLblFreeTxt;
	u32 m_systemLblFree;
	u32 m_systemLblIOSTxt;
	u32 m_systemLblIOS;
	u32 m_systemLblIOSbase;
	u32 m_systemBtnDownload;
	u32 m_systemLblInfo;
	u32 m_systemLblIosSelectVal;	
	u32 m_systemBtnIosSelectM;	
	u32 m_systemBtnIosSelectP;	
	u32 m_systemLblVerSelectVal;	
	u32 m_systemBtnVerSelectM;	
	u32 m_systemBtnVerSelectP;	

	bool m_reload;
	
	WPADData *wd[WPAD_MAX_WIIMOTES];
	void LeftStick();
	u8 pointerhidedelay[WPAD_MAX_WIIMOTES];
	u16 stickPointer_x[WPAD_MAX_WIIMOTES];
	u16 stickPointer_y[WPAD_MAX_WIIMOTES];
	
	u8 m_wpadLeftDelay;
	u8 m_wpadDownDelay;
	u8 m_wpadRightDelay;
	u8 m_wpadUpDelay;
	u8 m_wpadADelay;
	//u8 m_wpadBDelay;

	u8 m_padLeftDelay;
	u8 m_padDownDelay;
	u8 m_padRightDelay;
	u8 m_padUpDelay;
	u8 m_padADelay;
	//u8 m_padBDelay;
	
	u32 wii_btnsPressed;
	u32 wii_btnsHeld;
	u32 gc_btnsPressed;
	u32 gc_btnsHeld;

	bool m_show_pointer[WPAD_MAX_WIIMOTES];
	float left_stick_angle[WPAD_MAX_WIIMOTES];
	float left_stick_mag[WPAD_MAX_WIIMOTES];
	float right_stick_angle[WPAD_MAX_WIIMOTES];
	float right_stick_mag[WPAD_MAX_WIIMOTES];
	float wmote_roll[WPAD_MAX_WIIMOTES];
	s32   right_stick_skip[WPAD_MAX_WIIMOTES];
	s32	  wmote_roll_skip[WPAD_MAX_WIIMOTES];
	bool  enable_wmote_roll;

	void SetupInput(void);
	void ScanInput(void);

	void ButtonsPressed(void);
	void ButtonsHeld(void);

	bool lStick_Up(void);
	bool lStick_Right(void);
	bool lStick_Down(void);
	bool lStick_Left(void);

	bool rStick_Up(void);
	bool rStick_Right(void);
	bool rStick_Down(void);
	bool rStick_Left(void);

	bool wRoll_Left(void);
	bool wRoll_Right(void);

	bool wii_btnRepeat(s64 btn);
	bool gc_btnRepeat(s64 btn);

	bool WPadIR_Valid(int chan);
	bool WPadIR_ANY(void);
	
	volatile bool m_exit;
	volatile bool m_disable_exit;
	
	volatile bool m_thrdStop;
	volatile bool m_thrdWorking;

	float m_thrdStep;
	float m_thrdStepLen;

	mutex_t m_mutex;
	wstringEx m_thrdMessage;
	volatile float m_thrdProgress;
	volatile bool m_thrdMessageAdded;

	SSoundEffect m_cameraSound;

	bool m_video_playing;
	
	u32 m_loaded_ios_base;
	u32 m_locDol;
private:
	typedef std::pair<std::string, u32> FontDesc;
	typedef std::map<FontDesc, SFont> FontSet;
	typedef std::map<std::string, STexture> TexSet;
	typedef std::map<std::string, SSoundEffect> SoundSet;
	struct SThemeData
	{
		TexSet texSet;
		FontSet fontSet;
		SoundSet soundSet;
		SFont btnFont;
		SFont lblFont;
		SFont titleFont;
		SFont thxFont;
		CColor btnFontColor;
		CColor lblFontColor;
		CColor txtFontColor;
		CColor thxFontColor;
		CColor titleFontColor;
		STexture btnTexL;
		STexture btnTexR;
		STexture btnTexC;
		STexture btnTexLS;
		STexture btnTexRS;
		STexture btnTexCS;
		STexture pbarTexL;
		STexture pbarTexR;
		STexture pbarTexC;
		STexture pbarTexLS;
		STexture pbarTexRS;
		STexture pbarTexCS;
		STexture btnTexPlus;
		STexture btnTexPlusS;
		STexture btnTexMinus;
		STexture btnTexMinusS;
		SSoundEffect clickSound;
		SSoundEffect hoverSound;
		SSoundEffect cameraSound;
	};
	// 
	void _initErrorMenu(SThemeData &theme);
	void _initConfigMenu(SThemeData &theme);
	void _initConfigAdvMenu(SThemeData &theme);
	void _initConfig3Menu(SThemeData &theme);
	void _initConfig4Menu(SThemeData &theme);
	void _initConfigSndMenu(SThemeData &theme);
	void _initConfigScreenMenu(SThemeData &theme);
	void _initConfig7Menu(SThemeData &theme);
	void _initDownloadMenu(SThemeData &theme);
	void _initCodeMenu(SThemeData &theme);
	void _initAboutMenu(SThemeData &theme);
	void _initSystemMenu(SThemeData &theme);
	//
	void _textSystem(void);
	void _textMain(void);
	void _textError(void);
	void _textConfig(void);
	void _textConfig3(void);
	void _textConfigScreen(void);
	void _textConfig4(void);
	void _textConfig7(void);
	void _textConfigAdv(void);
	void _textConfigSnd(void);
	void _textDownload(void);
	void _textCode(void);
	void _textAbout(void);
	//
	void _hideError(bool instant = false);
	void _hideMain(bool instant = false);
	void _hideConfig(bool instant = false);
	void _hideConfig3(bool instant = false);
	void _hideConfigScreen(bool instant = false);
	void _hideConfig4(bool instant = false);
	void _hideConfig7(bool instant = false);
	void _hideConfigAdv(bool instant = false);
	void _hideConfigSnd(bool instant = false);
	void _hideDownload(bool instant = false);
	void _hideCode(bool instant = false);
	void _hideAbout(bool instant = false);
	void _hideSystem(bool instant = false);
	//
	void _showError(void);
	void _showMain(void);
	void _showConfig(void);
	void _showConfig3(void);
	void _showConfigScreen(void);
	void _showConfig4(void);
	void _showConfig7(void);
	void _showConfigAdv(void);
	void _showConfigSnd(void);
	void _showDownload(void);
	void _showCode(void);
	void _showAbout(void);
	void _showCheatSettings(void);
	void _showSystem(void);
	void _drawBg(void);
	void _updateText(void);
	// 
	void _config(int page);
	int _config1(void);
	int _config3(void);
	int _configScreen(void);
	int _config4(void);
	int _config7(void);
	int _configAdv(void);
	int _configSnd(void);
	void _download(void);
	bool _code(char code[4], bool erase = false);
	void _about(void);
	void _system(void);
	//
	void _mainLoopCommon(bool blockExit = false);
	// 
private:
	void _launchHomebrew(const char *filepath, safe_vector<std::string> arguments);
	void _setAA(int aa);

	void _buildMenus(void);
	void _showWaitMessage();
public:
	void _hideWaitMessage();
private:
	static void _showWaitMessages(CMenu *m);
	u32 _addButton(SThemeData &theme, const char *, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color);
	u32 _addPicButton(SThemeData &theme, const char *, STexture &texNormal, STexture &texSelected, int x, int y, u32 width, u32 height);
	u32 _addLabel(SThemeData, const char *, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, u16 style);
	u32 _addLabel(SThemeData, const char *, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, u16 style, STexture &bg);
	u32 _addProgressBar(SThemeData &theme, const char *, int x, int y, u32 width, u32 height);
	void _setHideAnim(u32 id, const char *, int dx, int dy, float scaleX, float scaleY);
	// 
	const wstringEx _t(const char *key, const wchar_t *def = L"") { return m_loc.getWString(m_curLanguage, key, def); }
	const wstringEx _fmt(const char *key, const wchar_t *def);
	// 
	void _setThrdMsg(const wstringEx &msg, float progress);
	static bool _downloadProgress(void *obj, int size, int position);

	void _listDOL(safe_vector<std::string> &v, const std::string &gameId);
	void _stopSounds(void);
	//

	static bool _updateProgress(void *obj, float progress);

	static void _load_installed_cioses();
	//
	struct SOption { const char id[10]; const wchar_t text[16]; };
	static const string _translations[23];
	static const SOption _languages[11];
	static const SOption _videoModes[7];
	static const SOption _vidModePatch[4];
	static const SOption _hooktype[8];
	static const SOption _exitTo[4];
	static const int _ios[6];
	struct SIOS 
	{ 
		u32 ios; 
		u32 ar_index; 
		bool operator==(const u32& i) const
		{
			return ios == i;
		}		
	};
	static safe_vector<SIOS> _installed_cios;
	static bool _sortByIOS(SIOS item1, SIOS item2);
	static int _version[9];
	static const int _nbCfgPages;
};

#define ARRAY_SIZE(a)		(sizeof a / sizeof a[0])

#endif // !defined(__MENU_HPP)
